﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using net.xBei.Models.Database;
using net.xBei.Models.json;

namespace net.xBei.Helper; 
/// <summary>
/// EF
/// </summary>
public static class EntityFrameworkHelper {
    /// <summary>
    /// 根据条件获取内容
    /// Where()和Select()的结合体
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="source">数据源</param>
    /// <param name="predicate">条件</param>
    /// <param name="selector">选取内容</param>
    /// <returns></returns>
    public static IQueryable<TResult> Get<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, Expression<Func<TSource, TResult>> selector) {
        return source.Where(predicate).Select(selector);
    }
    /// <summary>
    /// 按条件更新（延迟）字段，需要调用 DbContext.SaveChanges();
    /// 如果<paramref name="callBack"/>有复杂应用请使用<see cref="UpdateRealTime{T}(DbSet{T}, Expression{Func{T, bool}}, Func{T, T})"/>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="predicate"></param>
    /// <param name="callBack"></param>
    public static void Update<T>(this DbSet<T> entities, Expression<Func<T, bool>> predicate, Func<T, T> callBack) where T : class {
        entities.UpdateRange(entities.Where(predicate).Select(callBack));
    }
    /// <summary>
    /// 按条件更新（实时处理），需要调用 DbContext.SaveChanges();<br/>
    /// Entity Framework Core 7.0 以上请使用
    /// <see cref="RelationalQueryableExtensions.ExecuteUpdateAsync{TSource}(IQueryable{TSource}, Expression{Func{Microsoft.EntityFrameworkCore.Query.SetPropertyCalls{TSource}, Microsoft.EntityFrameworkCore.Query.SetPropertyCalls{TSource}}}, System.Threading.CancellationToken)"/>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="predicate"></param>
    /// <param name="callBack"></param>
    public static void UpdateRealTime<T>(this DbSet<T> entities, Expression<Func<T, bool>> predicate, Func<T, T> callBack) where T : class {
        entities.UpdateRange(entities.Where(predicate).ToArray().Select(callBack).ToArray());
    }
    /// <summary>
    /// 按条件删除记录，需要调用 DbContext.SaveChanges();
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="predicate"></param>
    public static void Remove<T>(this DbSet<T> entities, Expression<Func<T, bool>> predicate) where T : class {
        entities.RemoveRange(entities.Where(predicate));
    }
    /// <summary>
    /// 删除记录，需要调用 DbContext.SaveChanges();
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="db"></param>
    public static void Remove<T>(this IQueryable<T> entities, DbSet<T> db) where T : class {
        db.RemoveRange(entities);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TTable"></typeparam>
    /// <param name="query"></param>
    /// <param name="tables"></param>
    /// <returns></returns>
    public static IQueryable<TTable> FromQuery<TTable>(this TableQuery query, DbSet<TTable> tables) where TTable : class
        => tables.FromSqlRaw(query.ToSql(), query.Parameters);
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TTable"></typeparam>
    /// <param name="query"></param>
    /// <param name="fields"></param>
    /// <param name="tables"></param>
    /// <returns></returns>
    public static IQueryable<TTable> FromQuery<TTable>(this TableQuery query, string fields, DbSet<TTable> tables) where TTable : class
        => tables.FromSqlRaw(query.ToSql(fields), query.Parameters);
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TTable"></typeparam>
    /// <param name="query"></param>
    /// <param name="fields"></param>
    /// <param name="tables"></param>
    /// <returns></returns>
    public static IQueryable<TTable> FromQuery<TTable>(this TableQuery query, IEnumerable<string> fields, DbSet<TTable> tables) where TTable : class
        => tables.FromSqlRaw(query.ToSql(fields), query.Parameters);
    /// <summary>
    /// 查询是否存在
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <param name="source"></param>
    /// <param name="errHandler">返回的报错信息</param>
    /// <returns></returns>
    public static async Task<ResponseData<bool>> IsExistsAsync<TSource>([NotNull] this IQueryable<TSource> source,
                                                                        [NotNull] Func<string> errHandler)
        => (await source.AnyAsync()) ? ResponseData<bool>.Ok(true) : ResponseData<bool>.Error(errHandler.Invoke());
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <param name="source"></param>
    /// <param name="predicate"></param>
    /// <param name="errHandler">返回的报错信息</param>
    /// <returns></returns>
    public static async Task<ResponseData<bool>> IsExistsAsync<TSource>([NotNull] this IQueryable<TSource> source,
                                                                        [NotNull] Expression<Func<TSource, bool>> predicate,
                                                                        [NotNull] Func<string> errHandler)
        => (await source.AnyAsync(predicate)) ? ResponseData<bool>.Ok(true) : ResponseData<bool>.Error(errHandler.Invoke());
}
